<?php

namespace Biz\service\FineGoodsBrokeNews;

use Biz\cache\wiki\WikiBasicCounter;
use Biz\model\FineGoodsBrokeNews\FineGoodsBrokeNewsFavouriteLogModel;
use Biz\model\FineGoodsBrokeNews\FineGoodsBrokeNewsLogModel;
use Biz\model\FineGoodsBrokeNews\FineGoodsBrokeNewsModel;
use Biz\service\wiki\Wiki;
use Biz\tools\ArrayTool;
use Doraemon\cache\UserCounter;
use Doraemon\model\Photos as DbPhotos;
use Doraemon\pockets\constInterface\FormatScene;
use Doraemon\service\Photos;
use Doraemon\service\User as mUser;
use Doraemon\service\Format\Note\HandleNote;
use Doraemon\tools\HhzEnv;
use Doraemon\tools\Log;

class FineGoodsBrokeNewsService
{
    /** @var string[] 首页滚动弹幕文言 */
    public const TEXT_MAP = [
        FineGoodsBrokeNewsLogModel::DATA_TYPE_BROKE_NEWS => "刚刚更新了好物爆料",
        FineGoodsBrokeNewsLogModel::DATA_TYPE_NOTE => "刚刚更新了双11晒好物"
    ];

    /** @var array 趋势好物推荐 系统指定wiki */
    public const RECOMMEND_WIKI_ID_PRO = [169959, 121978, 166679, 186514];
    public const RECOMMEND_WIKI_ID_TEST = [6698, 6699, 6700, 6701];

    /** @var string 好物爆料指定话题ID */
    public const BROKE_NEWS_TOPIC_ID = "1396"; // 线上
    public const BROKE_NEWS_TOPIC_ID_TEST = "2333"; // 测试环境

    /** @var int 好物推荐 取用户真实数据数量 */
    public const USER_WIKI_COUNT = 6;

    /** @var int 用户卡片每页5条数据 */
    public const CARD_COUNT = 5;

    /** @var string 活动上线 第一天 */
    public const FIRST_DATE_START = "2021-11-11 08:00:00";

    /** @var string 每天几点开始 */
    public const FIRST_HOUR_START = "08:00:00";

    /** @var string 每天几点结束 */
    public const FIRST_HOUR_END = "22:00:00";

    /** @var int 每天收藏数增长多少个小时 */
    public const FAVOURITE_INCREASE_HOURS = 14;

    /** @var int 每小时最小增长 */
    public const MIN_INCREASE = 56;

    /** @var int 每小时最大增长 */
    public const MAX_INCREASE = 128;

    /** @var int 一天 */
    public const SECOND_BY_DAY = 3600 * 24;

    /** @var int 最小粉丝数 */
    public const MIN_FAV_COUNT = 500;

    /** @var string 世界开始时间 */
    public const DATETIME_START = "1970-01-01 00:00:00";

    /** @var array note质量 */
    public const NOTE_QUALITY = [DbPhotos::QUALITY_HIGH, DbPhotos::QUALITY_FEATURED];

    /**
     * 首页弹幕信息
     * @return array
     */
    public static function getCompleteLog(): array
    {
        $uidList = FineGoodsBrokeNewsLogModel::getLogs();
        $uidArray = array_column($uidList, 'uid');
        $userInfo = mUser::getUsers($uidArray);
        $list = [];
        foreach ($uidList as $index => $item) {
            $nick = mb_strlen($userInfo[$item['uid']]['nick']) > 8 ? mb_substr($userInfo[$item['uid']]['nick'], 0,
                    8) . "..." : $userInfo[$item['uid']]['nick'];
            $list[] = [
                'avatar' => $userInfo[$item['uid']]['avatar'] ?? '',
                'text' => $nick . self::TEXT_MAP[$item['data_type']]
            ];
        }

        return $list;
    }

    /**
     * 添加好物爆料日志
     * @param int $uid
     * @param $objID
     * @return bool|\PDOStatement
     */
    public static function addBrokeNewsLog(int $uid = 0, $objID)
    {
        $userInfo = UserCounter::getOne($uid);
        return FineGoodsBrokeNewsLogModel::addBrokeNewsLog($uid, $objID, $userInfo['fans']);
    }

    /**
     * 添加Note日志
     * @param array $data
     * @return bool|\PDOStatement
     */
    public static function addNoteLog(array $data = [])
    {
        $userInfo = UserCounter::getOne($data['uid']);
        $wiki = FineGoodsBrokeNewsModel::select(['note'], ['uid' => $data['uid'], 'pid' => 1]);
        if (empty($wiki)) {
            FineGoodsBrokeNewsModel::save([
                'pid' => 1,
                'uid' => $data['uid'],
                'fan_count' => $userInfo['fans'],
                'note' => json_encode([$data['id']]),
            ]);
        } else {
            $note = json_decode($wiki[0]['note'], true);
            $note[] = $data['id'];
            FineGoodsBrokeNewsModel::update([
                'note' => json_encode($note),
            ], ['uid' => $data['uid'], 'pid' => 1]);
            $maxPid = FineGoodsBrokeNewsModel::max('pid', [
                'uid' => $data['uid']
            ]);
            FineGoodsBrokeNewsModel::update([
                'edittime' => date("Y-m-d H:i:s"),
            ], ['uid' => $data['uid'], 'pid' => $maxPid]);
            FineGoodsBrokeNewsModel::update([
                'fan_count' => $userInfo['fans'],
            ], ['uid' => $data['uid']]);
        }
        return FineGoodsBrokeNewsLogModel::addNoteLog($data['uid'], $data['id'], $userInfo['fans']);
    }

    /**
     * 删除Note日志
     * @param array $data
     */
    public static function delNoteLog(array $data = [])
    {
        $userInfo = UserCounter::getOne($data['uid']);
        FineGoodsBrokeNewsLogModel::delLog($data['uid'], $data['id']);
    }

    /**
     * 保存好物爆料信息
     * @param array $data
     */
    public static function saveData(array $data = [])
    {
        $userInfo = UserCounter::getOne($data['uid']);
        $wiki = FineGoodsBrokeNewsModel::select(['wiki'], ['uid' => $data['uid'], 'pid' => 1]);
        if (empty($wiki)) {
            FineGoodsBrokeNewsModel::save([
                'pid' => 1,
                'uid' => $data['uid'],
                'fan_count' => $userInfo['fans'],
                'wiki' => $data['data'],
            ]);
            self::addBrokeNewsLog($data['uid'], 1);
        } else {
            if (empty($wiki[0]['wiki']) || $wiki[0]['wiki'] == 'null') {
                FineGoodsBrokeNewsModel::update([
                    'wiki' => $data['data'],
                    'edittime' => date("Y-m-d H:i:s"),
                ], ['uid' => $data['uid'], 'pid' => 1]);
                FineGoodsBrokeNewsModel::update([
                    'fan_count' => $userInfo['fans'],
                ], ['uid' => $data['uid']]);
                self::addBrokeNewsLog($data['uid'], 1);
            } else {
                $pid = FineGoodsBrokeNewsModel::getPid($data['uid']);
                FineGoodsBrokeNewsModel::save([
                    'pid' => $pid,
                    'uid' => $data['uid'],
                    'fan_count' => $userInfo['fans'],
                    'wiki' => $data['data'],
                ]);
                self::addBrokeNewsLog($data['uid'], $pid);
            }
        }
    }

    /**
     * 判断是否是参加双十一 话题ID
     * @param int $topicID
     * @return bool
     */
    public static function isBrokeNewsTopic(int $topicID): bool
    {
        if (HhzEnv::isGray() || HhzEnv::isProduction()) {
            $selfTopicId = self::BROKE_NEWS_TOPIC_ID;
        } else {
            $selfTopicId = self::BROKE_NEWS_TOPIC_ID_TEST;
        }
        return $topicID == $selfTopicId;
    }

    /**
     * 好物推荐
     * @param int $uid
     * @return array
     * @throws \Exception
     */
    public static function getRecommendList(int $uid = 0): array
    {
        $recommendWikiIdList = self::getPreRecommendList();
        $presetRecommendList = FineGoodsBrokeNewsFavouriteLogModel::select(['basic_id', 'fav_count'], [
            'basic_id' => $recommendWikiIdList,
        ]);
        $wikiList = self::getUserWikiInActivity();
        $list = array_merge($presetRecommendList, $wikiList);
        $listMap = array_column($list, 'fav_count', 'basic_id');
        $listIDs = array_column($list, 'basic_id');
        if (empty($listIDs)) {
            return [];
        } else {
            $wikiInfoList = self::getWikiLists($listIDs, $uid);
            foreach ($wikiInfoList as $index => $item) {
                $wikiInfoList[$index]['fav_count'] = (int)$listMap[$item['basic_id']];
            }
            $wikiInfoList = array_values($wikiInfoList);
            ArrayTool::arrayMultiSort($wikiInfoList, ['fav_count' => SORT_DESC]);
            return $wikiInfoList;
        }
    }

    private static function getPreRecommendList()
    {
        if (HhzEnv::isGray() || HhzEnv::isProduction()) {
            $recommendWikiIdList = self::RECOMMEND_WIKI_ID_PRO;
        } else {
            $recommendWikiIdList = self::RECOMMEND_WIKI_ID_TEST;
        }
        return $recommendWikiIdList;
    }

    public static function getUserWikiInActivity()
    {
        // 用户真实数据
        $wikiID = self::getwikiIDByUser();
        return (array)FineGoodsBrokeNewsFavouriteLogModel::select(['basic_id', 'fav_count'], [
            'basic_id' => $wikiID,
            "ORDER" => ['fav_count' => "DESC"],
            'LIMIT' => self::USER_WIKI_COUNT
        ]);
    }

    private static function getwikiIDByUser()
    {
        $userWikiList = FineGoodsBrokeNewsModel::select(['wiki']);
        $wikiID = array_merge(...array_map(function ($v) {
            if ($v['wiki'] == "null") {
                return [];
            } else {
                $v = json_decode($v['wiki'], true);
                $values = array_column($v, 'basic_id');
                return array_map(function ($v1) {
                    return (int)$v1;
                }, $values);
            }
        }, $userWikiList));
        $wikiBasicIDList = array_values(array_unique($wikiID));
        return array_values(array_diff($wikiBasicIDList, self::getPreRecommendList()));
    }

    /**
     * 获取wiki搜藏数
     * @param array $wikiIDList
     * @return array|array[]
     */
    public static function getWikiFavouriteCount(array $wikiIDList)
    {
        if (empty($wikiIDList) > 0) {
            return [];
        }
        $counter = WikiBasicCounter::getMulti($wikiIDList);
        return array_map(function ($v) use ($counter) {
            return [
                'basic_id' => $v,
                'fav_count' => isset($counter[$v]) ? $counter[$v][WikiBasicCounter::BASIC_FAVORITE] : 0
            ];
        }, $wikiIDList);
    }

    /**
     * 获取wiki卡片
     * @param array $wikiIDList wiki_basic 主键数组
     * @param int $uid
     * @return array
     * @throws \Exception
     */
    public static function getWikiLists(array $wikiIDList, int $uid = 0)
    {
        $rs = [];
        $list = Wiki::getWikiListByBasicIds($wikiIDList, $uid);
        foreach ($list as $item) {
            $rs[] = [
                'wiki_id' => $item['id'],
                'basic_id' => $item['basic_id'],
                'title' => $item['title'],
                'basic_state' => $item['basic_state'],
                'wiki_status' => $item['wiki_status'],
                'spec_img_url' => $item['cover_img'],
                'fav_count' => $item['fav_count'],
                'is_fav' => $item['is_fav'],
                'min_price' => $item['ori_min_price'],
                'max_price' => $item['ori_min_price'],
            ];
        }
        return $rs;
    }

    /**
     * 每小时增长数
     * @throws \Exception
     */
    public static function getIncreaseByHour(): int
    {
        $seconds = strtotime(date("Y-m-d 00:00:00")) - strtotime(date("Y-m-d 00:00:00",
                strtotime(self::FIRST_DATE_START)));
        $dayDiff = floor($seconds / self::SECOND_BY_DAY);
        $currentHoursDiff = floor((time() - strtotime(date('Y-m-d ' . self::FIRST_HOUR_START))) / 3600);
        $hoursDiff = $dayDiff * self::FAVOURITE_INCREASE_HOURS + $currentHoursDiff;
        return random_int($hoursDiff * self::MIN_INCREASE, $hoursDiff * self::MAX_INCREASE);
    }

    /**
     * 判断是否是第一天
     * @return bool
     */
    public static function isFirstDay(): bool
    {
        return strtotime(date('Y-m-d 00:00:00')) - strtotime(date('Y-m-d 00:00:00',
                strtotime(self::FIRST_DATE_START))) < self::SECOND_BY_DAY;
    }

    /**
     * 定时计算计算wiki结果
     */
    public static function wikiFavouriteCount()
    {
        $dateStart = strtotime(date("Y-m-d") . " " . self::FIRST_HOUR_START);
        $dateEnd = strtotime(date("Y-m-d") . " " . self::FIRST_HOUR_END);
        $now = time();
        if ($now >= $dateStart && $now <= $dateEnd) {
            $datetime = date("Y-m-d H:0:0");
            // 好物推荐 wiki id
            $recommendWikiIdList = self::getPreRecommendList();
            // 用户参加活动 wiki id
            $userWikiList = self::getwikiIDByUser();
            // 抽屉中的wiki id
            $drawerWikiID = DrawerService::getWikiID();
            // 用户发布Note关联的wiki
            $userNoteWikiList = self::getUserNoteWikiID();
            $list = array_values(array_unique(array_merge($recommendWikiIdList, $userWikiList, $drawerWikiID,
                $userNoteWikiList)));
            $count = count($list);
            $page = ceil($count / 100);
            for ($i = 0; $i < $page; $i++) {
                $wikiIDList = array_slice($list, $i * 100, 100);
                $historyList = FineGoodsBrokeNewsFavouriteLogModel::select(['fav_count', "basic_id"],
                    ["basic_id" => $wikiIDList]);
                $historyMap = array_column($historyList, null, 'basic_id');
                $historyBasicIDList = array_column($historyList, 'basic_id');
                $historyBasicFavourite = self::getWikiFavouriteCount($historyBasicIDList);
                $historyBasicFavouriteMap = array_column($historyBasicFavourite, 'fav_count', 'basic_id');
                foreach ($wikiIDList as $item) {
                    if (isset($historyMap[$item])) {
                        FineGoodsBrokeNewsFavouriteLogModel::update([
                            'fav_count' => $historyMap[$item]['fav_count'] + random_int(self::MIN_INCREASE,
                                    self::MAX_INCREASE),
                            'log_time' => $datetime
                        ], ['basic_id' => $item]);
                    } else {
                        FineGoodsBrokeNewsFavouriteLogModel::insert([
                            'basic_id' => $item,
                            'log_time' => $datetime,
                            'fav_count' => $historyBasicFavouriteMap[$item] + random_int(self::MIN_INCREASE,
                                    self::MAX_INCREASE)
                        ]);
                    }
                }
            }
        }
    }

    /**
     * 获取卡片列表
     * @param int $uid
     * @param int $lastID
     * @return array
     * @throws \Exception
     */
    public static function cardList(int $uid = 0, int $lastID = 0): array
    {
        $map = [
            "LIMIT" => self::CARD_COUNT
        ];
        if ($lastID > 0) {
            $lastEditTime = FineGoodsBrokeNewsModel::select(["edittime",'fan_count'], [
                'id' => $lastID,
                "ORDER" => ['id' => "DESC"]
            ]);
            $lastEditTimeValue = $lastEditTime[0]['edittime'];
            if (empty($lastEditTime)) {
                $lastEditTimeValue = self::DATETIME_START;
            }
            if(self::isFirstDay()){
                $fanList = FineGoodsBrokeNewsModel::select("id",[
                    "ORDER" => ["fan_count" => "DESC", "id" => "DESC"]
                ]);
                $index = array_search($lastID,$fanList);
                $tmp = array_slice($fanList,$index + 1,self::CARD_COUNT);
                $map['id'] = $tmp;
            }else{
                $map['edittime[<]'] = $lastEditTimeValue;
            }
        }
        if (self::isFirstDay()) {
            $map['fan_count[>=]'] = self::MIN_FAV_COUNT;
        }
        if (self::isFirstDay()) {
            $map['ORDER'] = ["fan_count" => "DESC", "id" => "DESC"];
        } else {
            $map['ORDER'] = ["edittime" => "DESC","id" => 'DESC'];
        }
        $list = FineGoodsBrokeNewsModel::select(["id", "uid", "wiki", "note", 'pid'], $map);
        if (empty($list)) {
            return [
                'list' => [],
                'is_over' => 1
            ];
        } else {
            $data = self::BuildUpCardInfo($list, $uid);
            return [
                'list' => $data,
                'is_over' => (int)empty($data)
            ];
        }
    }

    /**
     * 组装卡片数据
     * @param $list
     * @param $uid
     * @return array
     * @throws \Exception
     */
    public static function BuildUpCardInfo($list, $uid): array
    {
        $uidArray = array_column($list, 'uid');

        $where = [
            'uid' => $uidArray,
            "GROUP" => "uid",
        ];
        $userPid = FineGoodsBrokeNewsModel::getMaxPidPreUid($where);
        $userNote = FineGoodsBrokeNewsModel::getNotePreUid($uidArray);
        $userNoteLogList = self::getUserNoteID($uidArray);
        $data = [];

        $userInfoArr = mUser::getUsers($uidArray);
        $userInfoArr = array_column($userInfoArr, null, 'uid');
        foreach ($list as $item1) {
            $card = [];
            $card['id'] = $item1['id'];
            //用户数据
            $userInfo = $userInfoArr[$item1['uid']];
            // 参与活动的收藏数
            $userFavourite = 0;
            $card['user'] = [
                'id' => $item1['uid'],
                'avator_img' => $userInfo['avatar'],
                'nick' => $userInfo['nick'],
            ];
            // wiki
            $card['wiki'] = [];
            $userWikiID = [];
            if ($item1['wiki'] != 'null') {
                $wikiJson = json_decode($item1['wiki'], true);
                $wikiID = array_column($wikiJson, 'basic_id');
                $userWikiID = $wikiID;
                $wikiMap = array_column($wikiJson, 'comment', 'basic_id');
                $wikiList = self::getWikiLists($wikiID, $uid);
                $wikiFavouriteList = FineGoodsBrokeNewsFavouriteLogModel::select(['basic_id', 'fav_count'], [
                    'basic_id' => $wikiID
                ]);
                $wikiFavouriteMap = array_column($wikiFavouriteList, 'fav_count', 'basic_id');
                $wikiListMap = array_column($wikiList, null, 'basic_id');
                foreach ($wikiList as $index2 => $item2) {
                    $wikiList[$index2]['fav_count'] = (int)$wikiFavouriteMap[$item2['basic_id']];
                    $wikiList[$index2]['comment'] = $wikiMap[$item2['basic_id']];
                }
                foreach ($wikiJson as $wikiItem) {
                    $tmp = $wikiListMap[$wikiItem['basic_id']];
                    $tmp['fav_count'] = (int)$wikiFavouriteMap[$wikiItem['basic_id']];
                    $tmp['comment'] = $wikiMap[$wikiItem['basic_id']];
                    $card['wiki'][] = $tmp;
                }
            }
            // Note
            $note = [];
            $noteJson = [];
            if ($item1['pid'] == $userPid[$item1['uid']]) {
                $noteArray = $userNote[$item1['uid']];
                $noteArray = Photos::filterNoteIdByQuality($noteArray, self::NOTE_QUALITY);
                $noteJson = HandleNote::handleNote($noteArray, FormatScene::WIKI_MASONRY_LAYOUTS, 0);
                foreach ($noteJson as $index3 => $item3) {
                    $noteItem = [
                        'id' => $index3,
                        'title' => $item3['photo']['photo_info']['title'],
                        'remark' => $item3['photo']['photo_info']['remark'],
                        'cover_img' => $item3['photo']['photo_info']['image_list'][0]['ori_pic_url'] ?? '',
                    ];
                    $subWikiList = [];
                    foreach ($item3['photo']['wiki_info']['list'] as $item4) {
                        $subWikiList[] = [
                            'wiki_id' => $item4['id'],
                            'basic_id' => $item4['basic_id'],
                            'title' => $item4['title'],
                            'spec_img_url' => $item4['cover_img'],
                            'min_price' => $item4['ori_min_price'],
                            'max_price' => $item4['ori_max_price'],
                        ];
                    }
                    $noteItem['wiki'] = $subWikiList;
                    $note[] = $noteItem;
                }
            }
            if (!empty($note)) {
                $noteArray = [];
                $noteMap = array_column($note, null, 'id');
                foreach ($userNoteLogList[$item1['uid']] as $index7 => $item7) {
                    if (isset($noteMap[$item7])) {
                        $noteArray[] = $noteMap[$item7];
                    }
                }
                $card['note'] = $noteArray;
            } else {
                $card['note'] = [];
            }
            // 获取所有发布的wiki的basic_id
//            $brokeNewsList = FineGoodsBrokeNewsModel::select('wiki', [
//                'uid' => $item1['uid']
//            ]);
//            foreach ($brokeNewsList as $item5) {
//                if ($item5 != "null") {
//                    $wikiJson = json_decode($item5, true);
//                    $userWikiID = array_merge($userWikiID, array_column($wikiJson, 'basic_id'));
//                }
//            }
            // 获取所有发布的note关联wiki的basic_id
            $userNote1 = FineGoodsBrokeNewsModel::select("note", [
                'uid' => $item1['uid'],
                'pid' => 1
            ]);
            if ($userNote1[0] != 'null') {
                if (empty($noteJson)) {
                    $userNoteArray = json_decode($userNote1[0], true);
                    $userNoteArray = Photos::filterNoteIdByQuality($userNoteArray, self::NOTE_QUALITY);
                    $noteJson = HandleNote::handleNote($userNoteArray, FormatScene::WIKI_MASONRY_LAYOUTS, 0);
                }
                foreach ($noteJson as $item6) {
                    $userWikiID = array_merge($userWikiID,
                        array_column($item6['photo']['wiki_info']['list'], 'basic_id'));
                }
            }
            $userWikiID = array_values(array_unique($userWikiID));
            $wikiFavourite = FineGoodsBrokeNewsFavouriteLogModel::sum("fav_count", [
                'basic_id' => $userWikiID
            ]);
            $card['user']['fav_count'] = $wikiFavourite;
            if (count($card['note']) > 0 || count($card['wiki']) > 0) {
                $data[] = $card;
            }
        }
        return $data;
    }

    /**
     * 获取所有用户的NoteID 通过添加顺序倒序
     */
    private static function getUserNoteID($uidArray)
    {
        $logList = FineGoodsBrokeNewsLogModel::getNoteLog($uidArray);
        $userLogMap = [];
        foreach ($logList as $index => $item) {
            if (isset($userLogMap[$item['uid']])) {
                $userLogMap[$item['uid']][] = $item['obj_id'];
            } else {
                $userLogMap[$item['uid']] = [$item['obj_id']];
            }
        }
        return $userLogMap;
    }

    /**
     * 用户发布Note关联WikiID
     */
    private static function getUserNoteWikiID()
    {
        $userWikiID = [];
        $note = FineGoodsBrokeNewsModel::select(['note'], [
            'pid' => 1,
        ]);
        $note = array_merge(...array_map(function ($v) {
            if ($v['note'] == 'null') {
                return [];
            } else {
                return json_decode($v['note'], true);
            }
        }, $note));
        $userNoteArray = Photos::filterNoteIdByQuality($note, self::NOTE_QUALITY);
        $noteJson = HandleNote::handleNote($userNoteArray, FormatScene::WIKI_MASONRY_LAYOUTS, 0);
        foreach ($noteJson as $item6) {
            $userWikiID = array_merge($userWikiID, array_column($item6['photo']['wiki_info']['list'], 'basic_id'));
        }
        return $userWikiID;
    }
}